﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data.SqlTypes;

using Noris.Schedule.Support;
using Noris.Schedule.Support.Data;
using Noris.Schedule.Support.Sql;
using Noris.Schedule.Support.Core;
using Noris.Schedule.Support.DataFace;

using Noris.Schedule.Planning.DataFace;
using System.Collections;

namespace Noris.Schedule.Planning.ProcessData
{
	//    Komentář k T-Dokumentu:
	// Objekt třídy T-Dokument reprezentuje jeden konkrétní postup výroby jednoho dílce/výrobního příkazu pro danou technologii a množství.
	// Objekt neobsahuje konkrétní časy (termíny) výroby. Slouží jako obecná dokumentace pro plánování.
	// Objekt je univerzální nadstavbou nad konkrétními Noris třídami (VTPV / STPV / VP).
	// Tvorba objektu je řešena technikou ClassFactory: 
	//  objekt TDocumentCls má statický konstruktor CreateDocument(), 
	//  jemuž je (kromě specifikace konkrétního dílce) předána reference na objekt Factory, která naplní konkrétní data.
	// Objekt Factory je z hlediska Designu službou, která vrací potřebná data 
	//  (vyhledává operace, komponenty, zdroje a zajistí jejich konverzi na potřebný interface).
	// Skladba samotného objektu TDocumentCls je vždy stejná (hlavička, operace, na operacích zdroje a komponenty).
	// Data, která se do objektu umisťují, pocházejí z konkrétních Factory (jedna je pro STPV = třída TpvData, druhá pro VP = ProductData).
	// Vstupující data (operace, komponenty, zdroje) jsou třídy (např. Aps.ProcessData.TpvOperationCls), 
	//  které explicitně implementují potřebný interface (IOperationData), hostují v sobě základní datový objekt (AOperationCls) 
	//  a z tohoto datového objektu čtou a vracejí property povinné pro daný interface.
	//  Tyto "nadstavbové" třídy rozšiřují datovou základnu vstupních tříd 
	//  (např. ve třídě Aps.ProcessData.TpvOperationCls přidávají proměnné _QtyFinal a _QtyRequired, potřebné pro interface).
	// Do objektu TDocumentCls se umisťují přímo vrácené objekty.
	#region CLASS TDocumentCls : kompletní technologická dokumentace jednoho dílce podle jedné T modifikace anebo jednoho výrobního příkazu
	/// <summary>
	/// TDocumentCls : kompletní technologická dokumentace jednoho dílce podle jedné T modifikace / Výrobního příkazu.
	/// Obsahuje data o dílci, T modifikaci,  K modifikaci, soupis operací a soupis jejich komponent a zdrojů.
	/// </summary>
	public class TDocumentCls
	{
		#region KONSTRUKCE
		private TDocumentCls(TDocumentType documentType, int documentKey, decimal qtyFinal, TimeRange.TimeDirection timeDir)
		{
			_DocumentType = documentType;
			_DocumentKey = documentKey;
			_TimeDir = timeDir;
			_ConstrElementKey = SqlInt32.Null;
			_ConstrElement = null;
			_FictiousItemQtyToParallel = TFictiousItemQtyToParallelMode.NoChange;
			_AOperationModKey = SqlInt32.Null;
			_AOperationMod = null;
			_AStructureModKey = SqlInt32.Null;
			_AStructureMod = null;
			_QtyFinal = qtyFinal;
			_OperationList = new List<IOperationData>();
		}
		/// <summary> { get; }
		/// Určuje typ dokumentace, která je v tomto objektu aktuálně přítomna (VTPV, STPV, VP)
		/// </summary>
		internal TDocumentType DocumentType { get { return _DocumentType; } }
		private TDocumentType _DocumentType;
		/// <summary> { get; }
		/// Určuje číslo klíče dokumentu, má význam ve spojení s typem dokumentu DocumentType (VTPV, STPV, VP).
		/// Pro VTPV jde o DÍLEC
		/// Pro STPV jde o T MODIFIKACI
		/// Pro VP jde o VÝROBNÍ PŘÍKAZ
		/// </summary>
		internal int DocumentKey { get { return _DocumentKey; } }
		private int _DocumentKey;
		/// <summary> { get; }
		/// Určuje směr, ve kterém jsou setříděny operace = v tomto směru bude probíhat alokace kapacit.
		/// </summary>
		internal TimeRange.TimeDirection TimeDir { get { return _TimeDir; } }
		private TimeRange.TimeDirection _TimeDir;
		/// <summary> { get; set; }
		/// Klíč dílce, Null=neznáme (není určeno) 0=není dílec
		/// </summary>
		internal SqlInt32 ConstrElementKey { get { return _ConstrElementKey; } set { _ConstrElementKey = value; _ConstrElement = null; } }
		private SqlInt32 _ConstrElementKey;
		/// <summary> { get; set; }
		/// Data o dílci
		/// </summary>
		internal ConstrElementCls ConstrElement { get { return _ConstrElement; } set { _ConstrElement = value; _ConstrElementKey = (value == null ? SqlInt32.Null : value.RecordNumber); } }
		private ConstrElementCls _ConstrElement;
		/// <summary> { get; set; }
		/// Vliv jednotkového množství fiktivního dílce z kuovníku nadřízeného dílce
		/// na počet paralelních průchodů na jeho operacích (operace fiktivního dílce).
		/// </summary>
		internal TFictiousItemQtyToParallelMode FictiousItemQtyToParallel { get { return _FictiousItemQtyToParallel; } set { _FictiousItemQtyToParallel = value; } }
		private TFictiousItemQtyToParallelMode _FictiousItemQtyToParallel;
		/// <summary> { get; set; }
		/// Klíč T modifikace, Null=neznáme (není určeno) 0=není dílec
		/// </summary>
		internal SqlInt32 AOperationModKey { get { return _AOperationModKey; } set { _AOperationModKey = value; _AOperationMod = null; } }
		private SqlInt32 _AOperationModKey;
		/// <summary> { get; set; }
		/// Data o T modifikaci
		/// </summary>
		internal AOperationModCls AOperationMod { get { return _AOperationMod; } set { _AOperationMod = value; _AOperationModKey = (value == null ? SqlInt32.Null : value.RecordNumber); } }
		private AOperationModCls _AOperationMod;
		/// <summary> { get; set; }
		/// Klíč K modifikace, Null=neznáme (není určeno) 0=není dílec
		/// </summary>
		internal SqlInt32 AStructureModKey { get { return _AStructureModKey; } set { _AStructureModKey = value; _AStructureMod = null; } }
		private SqlInt32 _AStructureModKey;
		/// <summary> { get; set; }
		/// Data o K modifikaci
		/// </summary>
		internal AStructureModCls AStructureMod { get { return _AStructureMod; } set { _AStructureMod = value; _AStructureModKey = (value == null ? SqlInt32.Null : value.RecordNumber); } }
		private AStructureModCls _AStructureMod;
		/// <summary> { get; }
		/// Soupis operací. Každý jednotlivý záznam obsahuje data o operaci STPV, o standardní operaci, a seznam dat o komponentách.
		/// </summary>
		internal List<IOperationData> OperationList { get { return _OperationList; } }
		private List<IOperationData> _OperationList;
		/// <summary> { get; }
		/// Příznak platnosti dat (je vyplněna T Mod, K mod, Dílec)
		/// </summary>
		internal bool IsValid
		{
			get
			{
				return
					this.AOperationMod != null &&
					this.AStructureMod != null &&
					this.ConstrElement != null;
			}
		}
		/// <summary> { get; set; }
		/// Množství finálního výrobku, na které je dokumentace přepočítaná, anebo zbývá vyrobit z výrobního příkazu.
		/// </summary>
		internal decimal QtyFinal { get { return _QtyFinal; } set { _QtyFinal = value; } }
		private decimal _QtyFinal;
		/// <summary> { get; set; }
		/// Množství chybějící, toto se bere do plánu
		/// </summary>
		internal decimal QtyRequired { get { return _QtyRequired; } set { _QtyRequired = value; } }
		private decimal _QtyRequired;
		/// <summary> { get; set; }
		/// Příznak, že celá tato položka výroby je časově fixovaná (viz termíny FixedTime)
		/// </summary>
		internal bool IsFixed { get { return _IsFixed; } set { _IsFixed = value; } }
		private bool _IsFixed;
		/// <summary> { get; set; }
		/// Časový interval, do něhož je celá tato položka výroby fixována. Akceptuje se pouze pokud je IsFixed == true.
		/// </summary>
		internal TimeRange FixedTime { get { return _FixedTime; } set { _FixedTime = value; } }
		private TimeRange _FixedTime;
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{Type=" + DocumentType + "; Key=" + DocumentKey + "; T mod=" + this.AOperationMod + "; Oper.Count=" + this.OperationList.Count + "}";
		}
		#endregion
		#region TVORBA OBJEKTU TDocumentCls a IOperationData
		/// <summary>
		/// Statický konstruktor. Na základě předaného klíče T modifikace nebo Výrobního příkazu 
		/// a knihovny STPV / VP vygeneruje a vrátí plný objekt konkrétní dokumentace.
		/// Pokud nenajde některý klíčový údaj, nechá je prázdné (null).
		/// </summary>
		/// <param name="tDocumentKey">Klíč T modifikace STPV nebo výrobního příkazu, jednoznačně určuje technologii</param>
		/// <param name="qtyFinal">Konkrétní množství finálu, pro které se má dokumentace rozkalkulovat. Záleží na implementaci knihovny (tLibrary).</param>
		/// <param name="sortOrder">Požadavek na pořadí třídění seznamu operací: ToFuture = ASCENDING, ToHistory = DESCENDING, Stay = netřídit</param>
		/// <param name="tLibrary">Reference na kompletní knihovnu technologické dokumentace (STPV/VP).</param>
		/// <returns></returns>
		internal static TDocumentCls CreateDocument(int tDocumentKey, decimal qtyFinal, TimeRange.TimeDirection sortOrder, ITechnologyLibrary tLibrary, AuditorCls auditor)
		{
			return CreateDocument(tDocumentKey, qtyFinal, sortOrder, tLibrary, auditor, null, null);
		}
		/// <summary>
		/// Statický konstruktor. Na základě předaného klíče T modifikace nebo Výrobního příkazu 
		/// a knihovny STPV / VP vygeneruje a vrátí plný objekt konkrétní dokumentace.
		/// Pokud nenajde některý klíčový údaj, nechá je prázdné (null).
		/// </summary>
		/// <param name="tDocumentKey">Klíč T modifikace STPV nebo výrobního příkazu, jednoznačně určuje technologii</param>
		/// <param name="qtyFinal">Konkrétní množství finálu, pro které se má dokumentace rozkalkulovat. Záleží na implementaci knihovny (tLibrary).</param>
		/// <param name="sortOrder">Požadavek na pořadí třídění seznamu operací: ToFuture = ASCENDING, ToHistory = DESCENDING, Stay = netřídit</param>
		/// <param name="tLibrary">Reference na kompletní knihovnu technologické dokumentace (STPV/VP).</param>
		/// <param name="fiFinder">Odkaz na metodu, která vyhledá klíč T dokumentu pro daný fiktivní dílec. Pokud nebude předáno, pak se fiktivní dílce nebudou rozpadat ale dostanou se na osu S.</param>
		/// <param name="userData">Objekt s uživatelskými daty, který se předává do metody fiFinder</param>
		/// <returns></returns>
        internal static TDocumentCls CreateDocument(int tDocumentKey, decimal qtyFinal, TimeRange.TimeDirection sortOrder, ITechnologyLibrary tLibrary, AuditorCls auditor, GetFictiousItemDocKeyDelegate fiFinder, object userData)
		{
			if (tLibrary == null) return null;

			// Základ dokumentu = jeho typ, klíč a finální množství:
			TDocumentCls finalDocument = new TDocumentCls(tLibrary.CurrentType, tDocumentKey, qtyFinal, sortOrder);
			if (tDocumentKey == 0) return finalDocument;

			// Hlavičková data = Základní tři objekty (T modifikace, K modifikace, Dílec):
			tLibrary.GetTDocumentData(finalDocument, qtyFinal);

			// Seznam operací, kvůli fiktivním komponentám může jít o rekurzivní algoritmus:
			CreateDocumentAddOpArgs opArgs = new CreateDocumentAddOpArgs(finalDocument, sortOrder, tLibrary, fiFinder, userData);
            _CreateDocumentAddOperations(opArgs, tDocumentKey, 1M, qtyFinal, null, auditor);

			return finalDocument;
		}
		/// <summary>
		/// Do předaného T dokumentu (objekt tDocument) přidá operace patřící uvedenému T dokumentu (parametr tDocumentKey).
		/// Toto řešení umožní rekurzivní volání této metody pro vkládání rozpadu fiktivních dílců.
		/// </summary>
		/// <param name="opArgs">Neměnná data (finální technologie, třídění času, technologická knihovna, metoda pro hledání T modifikací fiktivních dílců)</param>
		/// <param name="tDocumentKey">Klíč T dokumentu, jehož operace a komponenty se nyní mají přidat (nemusí to být klíč tDocument, ale některý z nižších fiktivních dílců).</param>
		/// <param name="qtyOne">Množství jednotkové. Má význam jen u fiktivních dílců, pro které může někdy ovlivňovat počet paralelních průchodů.</param>
		/// <param name="qtyFinal">Množství, na které má být přepočtena daná T dokumentace tDocumentKey</param>
		/// <param name="parentOperation">Rodičovská operace, v níž se vyskytuje fiktivní dílec (anebo null, když se vytváří technologie pro hlavní dílec)</param>
        private static void _CreateDocumentAddOperations(CreateDocumentAddOpArgs opArgs, int tDocumentKey, decimal qtyOne, decimal qtyFinal, IOperationData parentOperation, AuditorCls auditor)
		{
			// Došlo zde k zacyklení?
			if (opArgs.ContainDocKey(tDocumentKey))
			{
                if (auditor != null)
                {
                    RecordCls tDocRecordMain = opArgs.TLibrary.GetTDocumentRecord(opArgs.FinalTDocumentKey, NotFindMode.Null);    // Záznam hlavičky TDoc hlavního dílce
                    RecordCls tDocRecordCurr = opArgs.TLibrary.GetTDocumentRecord(tDocumentKey, NotFindMode.Null);                // Záznam hlavičky TDoc zdejšího dílce
                    auditor.AddInfo(PlanningResultSeverityType.UserError, PlanningResultCircumstanceType.TechnologyFictiousItemCycle, (IRecordKey)tDocRecordCurr,
                        MessageInfo.Get("Chyba v technologii dílce %0: fiktivní dílec %1 je zacyklený (používá sám sebe).",
                        (tDocRecordMain == null ? "null" : tDocRecordMain.ReferNazev),
                        (tDocRecordCurr == null ? "null" : tDocRecordCurr.ReferNazev)));
                }
                return;
			}

			// Je tato technologie fiktivní (= když má parent operaci !)?
			bool thisIsFictious = (parentOperation != null);

			// Pokud je dílec fiktivní, zajímá mě režim přenosu množství jednotkového do počtu paralelních průchodů:
			TFictiousItemQtyToParallelMode fictItemQtyToParall = TFictiousItemQtyToParallelMode.NoChange;
			if (thisIsFictious)
				fictItemQtyToParall = opArgs.GetFictItemQtyToParallel(tDocumentKey);

			// Budou se provádět rozpady fiktivních dílců? (To platí pro všechny operace a jejich komponenty):
			bool decompositeFictiousItem = opArgs.DecompositeFictiousItem;

			// true = operaci (targetOperation) vložit do finální technologie PŘED rozpad fiktivních dílců,
			// false = vložit targetOperation za rozpad fiktivních dílců:
			bool operBeforeFict = (opArgs.SortOrder == TimeRange.TimeDirection.ToHistory);

			// Operace dané technologie:
			List<IOperationData> aopList = opArgs.GetOperationDataList(tDocumentKey, qtyFinal);
			if (aopList != null)
			{
				foreach (IOperationData operation in aopList)
				{
					// DAJ 0037299 2010-12-17: pokud je použit fiktivní dílec, a některá jeho operace je shodná s operací pro rychlé schválení,
					//  pak taková operace nepatří do fyzické technologie (nevkládá se tam), a její komponenty se navazují na parent operaci:
					bool realOperation = true;          // true = reálná operace, která půjde do finální technologie
					if (thisIsFictious && operation.DocumentType == TDocumentType.PlanApproved && operation.StandardMfrOperation == opArgs.MfrConfigExpressOperation)
						realOperation = false;          // false = neviditelná operace, její komponenty a zdroje půjdou do parent operace.

					// DAJ 0037299 : Pokud je to reálná operace (půjde do technologie), a přitom je z fiktivního dílce (to pochází z parenta),
					//  může dojít k uplatnění úpravy počtu paralelních průchodů podle jednotkového množství dílců:
					if (realOperation && thisIsFictious)
						_CreateDocumentModifyOperationsParallel(operation, fictItemQtyToParall, qtyOne);

					// Komponenty vstupní operace:
					//   (některá z komponent může být fiktivní, takové si vyřešíme jinak, a nebudou se vkládat do její operace:
					List<IStructureData> structList = opArgs.GetStructureDataList(operation.Operation, qtyFinal);
					
					// Cílová operace pro vkládání komponent a zdrojů operace je buď tato operace osobně, anebo parent (viz předešlé podmínky):
					IOperationData targetOperation = (realOperation ? operation : parentOperation);

					// Roztřídit komponenty na běžné a na fiktivní (běžné do target operace, fiktivní do seznamu ke zpracování):
					List<IStructureData> fictItList = new List<IStructureData>();     // Souhrn fiktivních komponent
					foreach (IStructureData structItem in structList)
					{
						if (structItem.FictiousItem && decompositeFictiousItem)
							// Fiktivní komponenta, a T library ji dokáže rozpadnout?
							fictItList.Add(structItem);
						else
							// Ne-fiktivní komponenty vkládám do target operace (což je buď tato, anebo parent operace):
							targetOperation.StructureList.Add(structItem);
					}

					// Zdroje operací jsou jednoduché, načtou se z T-Library a vloží do target operace:
					targetOperation.ResourceList.AddRange(opArgs.GetResourceDataList(operation.Operation, qtyFinal));

					// Směr času (odráží se v proměnné operBeforeFict): 
					//  zdejší operaci vkládáme buď dříve než operace fiktivních dílců, nebo až po nich.
					//  A to jen tehdy, když zdejší operace je reálná (nejde o operaci rychlého schválení na fiktivním dílci).

					// Nyní máme sestavenou operaci (operation), která patří do tDocument._OperationList.
					if (realOperation && operBeforeFict)
						// Pokud operace je reálná, a patří před fiktivní dílce:
						opArgs.AddOperation(targetOperation);

					// Vložit rozpady fiktivních dílců:
					foreach (IStructureData fictItItem in fictItList)
					{	// Každý fiktivní dílec v aktuální operaci:
						int fictItemKey = opArgs.FindFictiousItemKey(fictItItem);   // Vyhledám klíč T dokumentu tohoto fiktivního dílce
						if (fictItemKey != 0)
						{	// Rekurzivně zavolám rozepsání operací tohoto fiktivního dílce do výstupní T dokumentace:
							// Jako parent operaci posílám target operaci, tím zajistím, že v případě použití 
							//   neviditelné operace ("rychlé schválení") na nižší úrovni 
							//   budou její komponenty přidány do nejbližší vyšší nadřízené operace:
							_CreateDocumentAddOperations(opArgs, fictItemKey, fictItItem.QtyOne, fictItItem.QtyRequired, targetOperation, auditor);
						}
					}

					// Pokud operace je reálná, a patří za fiktivní dílce, přidáme ji až nyní:
					if (realOperation && !operBeforeFict)
						opArgs.AddOperation(targetOperation);
				}
			}

			opArgs.RemoveDocKey(tDocumentKey);  // S touto položkou jsme skončili, zacyklení nenastane, ale příště ji lze opět vložit.
		}
		/// <summary>
		/// Metoda modifikuje počet paralelních průchodů na operaci podle jednotkového množství komponenty s fiktivním dílcem
		/// </summary>
		/// <param name="operation">Operace</param>
		/// <param name="fictItemQtyToParall">Režim modifikace</param>
		/// <param name="qtyOne">Jednotkové množství komponenty s fiktivním dílcem</param>
		private static void _CreateDocumentModifyOperationsParallel(IOperationData operation, TFictiousItemQtyToParallelMode fictItemQtyToParall, decimal qtyOne)
		{
			switch (fictItemQtyToParall)
			{
				case TFictiousItemQtyToParallelMode.NoChange:
					break;
				case TFictiousItemQtyToParallelMode.SetQtyToParallelCount:
					if (qtyOne > 0M)
						_CreateDocumentModifyOperationsParallelSetQtyOne(operation, qtyOne);
					break;
				case TFictiousItemQtyToParallelMode.SetRatioToParallelCount:
					if (qtyOne > 0M && qtyOne < 1M)
						_CreateDocumentModifyOperationsParallelSetQtyOne(operation, qtyOne);
					break;
			}
		}
		/// <summary>
		/// Metoda upraví zadanou operaci tak, aby její počet ParalelPassingCount byl roven hodnotě dané parametrem qtyOne,
		/// a její UnitCount = 1M / qtyOne.
		/// Výše uvedené platí při vstupních hodnotách ParalelPassingCount = 1 a UnitCount = 1.
		/// Pokud jsou výchozí hodnoty ParalelPassingCount a UnitCount jiné, pak do nich vloží vstupní množství qtyOne přiměřeně upravené.
		/// </summary>
		/// <param name="operation">Operace fiktivního dílce, která se bude vepisovat do technologie. Fiktivní dílec pochází z pořadače, který předepisuje převod jednotkového množství do počtu paralelních průchodů.</param>
		/// <param name="qtyOne">Jednotkové množství fiktivního dílce v kusovníku nadřízeného dílce. Musí být větší než 0.</param>
		private static void _CreateDocumentModifyOperationsParallelSetQtyOne(IOperationData operation, decimal qtyOne)
		{
			if (qtyOne > 0M)
			{
				operation.ParalelPassingCount = operation.ParalelPassingCount * qtyOne;
				operation.UnitCount = operation.UnitCount / qtyOne;
			}
		}
		/// <summary>
		/// Vytvoří a vrátí data o požadované operaci
		/// </summary>
		/// <param name="tDocumentKey">Klíč dokumentu (Dílec VTPV, T-modifikace STPV, Výrobní příkaz)</param>
		/// <param name="operation">Klíč operace v rámci dílce</param>
		/// <param name="qtyFinal">Konkrétní množství finálu, pro které se má dokumentace rozkalkulovat. Záleží na implementaci knihovny (tLibrary).</param>
		/// <param name="tLibrary">Reference na kompletní knihovnu technologické dokumentace (STPV/VP).</param>
		/// <returns></returns>
		internal static IOperationData CreateOperation(int tDocumentKey, int operation, decimal qtyFinal, ITechnologyLibrary tLibrary, NotFindMode notFindMode)
		{
			IOperationData operationData = tLibrary.GetOperationData(tDocumentKey, operation, qtyFinal, notFindMode);
			if (operationData != null)
			{
				operationData.StructureList.AddRange(tLibrary.GetStructureDataList(operationData.Operation, qtyFinal));
				operationData.ResourceList.AddRange(tLibrary.GetResourceDataList(operationData.Operation, qtyFinal));
			}
			return operationData;
		}
		/// <summary>
		/// Metoda upraví zadanou operaci tak, aby její počet ParalelPassingCount byl roven hodnotě dané parametrem qtyOne,
		/// a její UnitCount = 1M / qtyOne.
		/// Výše uvedené platí při vstupních hodnotách ParalelPassingCount = 1 a UnitCount = 1.
		/// Pokud jsou výchozí hodnoty ParalelPassingCount a UnitCount jiné, pak do nich vloží vstupní množství qtyOne přiměřeně upravené.
		/// </summary>
		/// <param name="operation">Data operace.</param>
		/// <param name="qtyOne">Jednotkové množství fiktivního dílce v kusovníku nadřízeného dílce. Musí být větší než 0.</param>
		internal static void SetQtyOneToOperationParallel(IOperationData operation, decimal qtyOne)
		{
			_CreateDocumentModifyOperationsParallelSetQtyOne(operation, qtyOne);
		}
		/// <summary>
		/// Vytvoří a vrátí testovací T dokument. Je prázdný, obsahuje jen předané údaje, ale žádné operace.
		/// </summary>
		/// <param name="docType">Typ dokumentu</param>
		/// <param name="tDocumentKey">Klíč dokumentu</param>
		/// <param name="qtyFinal">Finální množství</param>
		/// <param name="sortOrder">Směr dokumentu</param>
		/// <returns></returns>
		internal static TDocumentCls CreateDocumentTest(TDocumentType docType, int tDocumentKey, decimal qtyFinal, TimeRange.TimeDirection sortOrder)
		{
			TDocumentCls tDocument = new TDocumentCls(docType, tDocumentKey, qtyFinal, sortOrder);
			return tDocument;
		}
		#endregion
	}
	#endregion
	#region CLASS CreateDocumentAddOpArgs : argumenty (data) pro metodu TDocumentCls._CreateDocumentAddOperations()
	/// <summary>
	/// CreateDocumentAddOpArgs : argumenty (data) pro metodu TDocumentCls._CreateDocumentAddOperations().
	/// Dat je mnoho, často putují ty samé objekty opakovaně stále dokola (metoda je rekurzivní).
	/// </summary>
	internal class CreateDocumentAddOpArgs
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="finalTDocument">Objekt finálního T dokumentu, do něhož se přidávají operace včetně jejich komponent</param>
		/// <param name="sortOrder">Směr setřídění operací</param>
		/// <param name="tLibrary">Technologická knihovna</param>
		/// <param name="fiFinder">Odkaz na metodu, která vyhledá klíč T dokumentu pro daný fiktivní dílec. Pokud nebude předáno, pak se fiktivní dílce nebudou rozpadat ale dostanou se na osu S.</param>
		/// <param name="userData">Objekt s uživatelskými daty, který se předává do metody fiFinder</param>
		internal CreateDocumentAddOpArgs(TDocumentCls finalTDocument, TimeRange.TimeDirection sortOrder, ITechnologyLibrary tLibrary, GetFictiousItemDocKeyDelegate fiFinder, object userData)
		{
			this.FinalTDocument = finalTDocument;
			this.SortOrder = sortOrder;
			this.TDocHt = new Hashtable();
			this.TLibrary = tLibrary;
			this.FiFinder = fiFinder;
			this.UserData = userData;

			MfrModulConfigCls mfrCfg = PlanningParametersCls.Current.MfrModulConfig;
			this.MfrConfigExpressOperation = 0;
			if (mfrCfg != null && !mfrCfg.ExpressOperation.IsNull)
				this.MfrConfigExpressOperation = mfrCfg.ExpressOperation.Value;
		}
		/// <summary>
		/// Objekt finálního T dokumentu, do něhož se přidávají operace včetně jejich komponent
		/// </summary>
		internal TDocumentCls FinalTDocument { get; private set; }
		/// <summary>
		/// Klíč standardní operace, která je zvolena jako operace rychlého schválení v konfiguraci modulu výroba, na záložce TPV
		/// (DAJ 0037299)
		/// </summary>
		internal int MfrConfigExpressOperation { get; private set; }
		/// <summary>
		/// Klíč finálního T dokumentu, do něhož se přidávají operace včetně jejich komponent
		/// </summary>
		internal int FinalTDocumentKey { get { return this.FinalTDocument.DocumentKey; } }
		/// <summary>
		/// Směr setřídění operací
		/// </summary>
		internal TimeRange.TimeDirection SortOrder { get; private set; }
		/// <summary>
		/// Soupis klíčů, které jsou přidány "nade mnou": 
		/// pokud na vstupu do této metody v tDocHt existuje klíč (tDocumentKey), pak jde o rekurzivní zacyklení.
		/// Jde o obranu proti zacyklení rekurze rozpadu vnořených fiktivních dílců.
		/// </summary>
		internal Hashtable TDocHt { get; private set; }
		/// <summary>
		/// Technologická knihovna
		/// </summary>
		internal ITechnologyLibrary TLibrary { get; private set; }
		/// <summary>
		/// Odkaz na metodu, která vyhledá klíč T dokumentu pro daný fiktivní dílec. Pokud nebude předáno, pak se fiktivní dílce nebudou rozpadat ale dostanou se na osu S.
		/// </summary>
		internal GetFictiousItemDocKeyDelegate FiFinder { get; private set; }
		/// <summary>
		/// Objekt s uživatelskými daty, který se předává do metody fiFinder
		/// </summary>
		internal object UserData { get; private set; }
		/// <summary>
		/// Příznak, zda je nyní podporován rozklad fiktivních dílců (musí to podporovat T Library a musí být zadaný handler FiFinder)
		/// </summary>
		internal bool DecompositeFictiousItem
		{
			get { return (this.TLibrary.AllowFictiousItem && this.FiFinder != null); }
		}
		/// <summary>
		/// Metoda najde a vrátí seznam operací k danému klíči dokumentu a množství.
		/// T Library a směr času použije svůj.
		/// Musí vrátit vždy nově vytvořené objekty, jejichž set property nesmí zapisovat do podkladových trvalých dat.
		/// Setované property slouží pro modifikaci dat v T dokumentaci pro konkrétní výrobu, z nich se vytvoří task, a tento objekt se uvolní.
		/// Podkladová data se nesmí změnit.
		/// </summary>
		/// <param name="tDocumentKey"></param>
		/// <param name="qtyFinal"></param>
		/// <returns></returns>
		internal List<IOperationData> GetOperationDataList(int tDocumentKey, decimal qtyFinal)
		{
			return this.TLibrary.GetOperationDataList(tDocumentKey, this.SortOrder, qtyFinal, NotFindMode.GetFromDbNull);
		}
		/// <summary>
		/// Metoda najde a vrátí seznam komponent k danému klíči operace a množství.
		/// T Library použije svůj.
		/// </summary>
		/// <param name="tOperationKey"></param>
		/// <param name="qtyFinal"></param>
		/// <returns></returns>
		internal List<IStructureData> GetStructureDataList(int tOperationKey, decimal qtyFinal)
		{
			return this.TLibrary.GetStructureDataList(tOperationKey, qtyFinal);
		}
		/// <summary>
		/// Metoda najde a vrátí seznam zdrojů operací k danému klíči operace a množství.
		/// T Library a směr času použije svůj.
		/// </summary>
		/// <param name="tOperationKey"></param>
		/// <param name="qtyFinal"></param>
		/// <returns></returns>
		internal List<IResourceData> GetResourceDataList(int tOperationKey, decimal qtyFinal)
		{
			return this.TLibrary.GetResourceDataList(tOperationKey, qtyFinal);
		}
		/// <summary>
		/// Metoda zjistí, zda ve své paměti TDocHt již obsahuje daný klíč dokumentu.
		/// Pokud ano, vrací true.
		/// Pokud ne, zapamatuje si ho a vrátí false.
		/// </summary>
		/// <param name="documentKey"></param>
		/// <returns></returns>
		internal bool ContainDocKey(int documentKey)
		{
			if (this.TDocHt.ContainsKey(documentKey))
				return true;
			this.TDocHt.Add(documentKey, null);
			return false;
		}
		/// <summary>
		/// Ze své paměti TDocHt odebere záznam daného klíče.
		/// </summary>
		/// <param name="documentKey"></param>
		internal void RemoveDocKey(int documentKey)
		{
			if (this.TDocHt.ContainsKey(documentKey))
				this.TDocHt.Remove(documentKey);
		}
		/// <summary>
		/// Do finálního T dokumentu přidá danou operaci (v níž je seznam komponent a zdrojů).
		/// </summary>
		/// <param name="operation"></param>
		internal void AddOperation(IOperationData operation)
		{
			this.FinalTDocument.OperationList.Add(operation);
		}
		/// <summary>
		/// Metoda najde a vrátí klíč technologie pro daný fiktivní dílec.
		/// Využívá se k tomu delegát na vyhledávací metodu FiFinder a objekt UserData.
		/// </summary>
		/// <param name="structureData">Data o fiktivním dílci (komponenta)</param>
		/// <returns></returns>
		internal int FindFictiousItemKey(IStructureData structureData)
		{
			return this.FiFinder(structureData, this.UserData);
		}
		/// <summary>
		/// Metoda najde a vrátí z T-Library informaci o režimu převodu množství fiktivní komponenty do počtu paralelních průchodů.
		/// </summary>
		/// <param name="tDocumentKey"></param>
		/// <returns></returns>
		internal TFictiousItemQtyToParallelMode GetFictItemQtyToParallel(int tDocumentKey)
		{
			return this.TLibrary.GetFictItemQtyToParallel(tDocumentKey);
		}
	}
	#endregion
}
